// Created by Windward Studios - no copyright is claimed. This code can be used in
// any manner by anyone for any reason. There is no copyright of any kind on it. You may
// use it in commercial products. You may change it without sharing those changes.
// We ask that you keep the "created by Windward Studios" in a comment at the top.

using System;
using System.Data;
using System.Data.Common;
using Kailua.net.windward.utils;

namespace net.windward.utils.ado.DB2
{
	/// <summary>
	/// Wraps a DbCommand object and provides a client independent method of setting parameters. All parameters are
	/// set as ? in the sql commands are are set based on their order. This also has an ExecuteInsert that if given
	/// a sql command to insert a single row, will return the value of the auto primary key for that row.
	/// </summary>
	class WrDB2Command : WrCommand
	{
		private readonly DbProviderFactory provider;
		private readonly IWrSyntax syntax;

		/// <summary>
		/// Create a DbCommand wrapper.
		/// </summary>
		/// <param name="provider">The provider for this command.</param>
		public WrDB2Command(DbProviderFactory provider)
		{
			this.provider = provider;
			syntax = new WrDB2Syntax(provider);
			cmd = provider.CreateCommand();
			cmd.CommandType = CommandType.Text;
		}

		/// <summary>
		/// Set the value of a parameter.
		/// </summary>
		/// <param name="ind">The index of this paramater in the command.</param>
		/// <param name="value">The value of this parameter.</param>
		public override void Set(int ind, object value)
		{

			if (value == null)
				value = DBNull.Value;

			DbParameter param = provider.CreateParameter();
			param.ParameterName = "@p" + ind;
			// DB2 does not handle the types that are less than an Int16 correctly
			if ((value is byte) || (value is bool) || (value is SByte))
				param.Value = Convert.ToInt16(value);
			else
				param.Value = value;

			cmd.Parameters.Add(param);
		}

		///<summary>
		///Used for inserting a row with an auto primary key. Executes an SQL statement against the Connection object of a .NET Framework 
		/// data provider, and returns the value of the primary key.
		///</summary>
		/// <param name="pkName">The name of the primary key being automatically set.</param>
		///<returns>
		///The value of the primary key for the inserted row.
		///</returns>
		///<exception cref="T:System.InvalidOperationException">The connection does not exist -or- The connection is not open. </exception><filterpriority>2</filterpriority>
		public override long ExecuteInsert(string pkName)
		{
			cmd.CommandText = "select " + pkName + " from final table (" + cmd.CommandText + ")";
			using (IDataReader rdr = cmd.ExecuteReader())
			{
				rdr.Read();
				return rdr.GetInt64(0);
			}
		}

		#region IDbCommand overrides

		///<summary>
		///Gets or sets the text command to run against the data source.
		///</summary>
		///<returns>
		///The text command to execute. The default value is an empty string ("").
		///</returns>
		///<filterpriority>2</filterpriority>
		public override string CommandText
		{
			get
			{
				return cmd.CommandText;
			}
			set
			{
				cmd.CommandText = syntax.ConvertSelect(value);
			}
		}

		///<summary>
		///Executes the <see cref="P:System.Data.IDbCommand.CommandText"></see> against the 
		/// <see cref="P:System.Data.IDbCommand.Connection"></see> and builds an <see cref="T:System.Data.IDataReader"></see>.
		///</summary>
		///
		///<returns>
		///An <see cref="T:System.Data.IDataReader"></see> object.
		///</returns>
		///<filterpriority>2</filterpriority>
		public override IDataReader ExecuteReader()
		{
			return new WrDB2DataReader(cmd.ExecuteReader());
		}

		///<summary>
		///Executes the <see cref="P:System.Data.IDbCommand.CommandText"></see> against the 
		/// <see cref="P:System.Data.IDbCommand.Connection"></see>, and builds an <see cref="T:System.Data.IDataReader"></see> 
		/// using one of the <see cref="T:System.Data.CommandBehavior"></see> values.
		///</summary>
		///
		///<returns>
		///An <see cref="T:System.Data.IDataReader"></see> object.
		///</returns>
		///
		///<param name="behavior">One of the <see cref="T:System.Data.CommandBehavior"></see> values. </param>
		/// <filterpriority>2</filterpriority>
		public override IDataReader ExecuteReader(CommandBehavior behavior)
		{
			Trap.trap();
			return new WrDB2DataReader(cmd.ExecuteReader(behavior));
		}

		#endregion
	}
}
